package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.controller.CourseBaseAuditController;
import com.xuecheng.content.convert.EntityMapper;
import com.xuecheng.content.convert.EntityMapperPo;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;

    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;

    /*
    1.判断传入的分页查询是否合法（如果是负数进行更改）
    2.调用MP分页查询API对象
    3.为分页查询设置条件（判断条件内容是否为空）
    4.调用方法根据条件查询页面数据
    5。获取当前页数据和总数量
    6.判断当前页数据是否为空，否的话使用mapstruct转换接口把po实体类的数据转换成DTO数据封装到PageVo返回给前端

    提交后查询审核数据也在这
     */
    @Override
    public PageVO queryCourseList(PageRequestParams params, QueryCourseModel model,Long companyId) {
        //判断传入的页面参数是否合法
        if (params.getPageNo()<1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }


        //设置MP分页查询对象
        Page<CourseBase> courseBasePage = new Page<>(params.getPageNo(), params.getPageSize());
        //设置查询lambd对象
        LambdaQueryWrapper<CourseBase> courseBaseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //配置条件
        courseBaseLambdaQueryWrapper.like(!StringUtil.isBlank(model.getCourseName()), CourseBase::getName, model.getCourseName());
        courseBaseLambdaQueryWrapper.eq(!StringUtil.isBlank(model.getAuditStatus()), CourseBase::getAuditStatus, model.getAuditStatus());

        // 添加对公司的查询条件   区分是否需要查询本机构下的数据
        if (!ObjectUtils.nullSafeEquals(companyId, CourseBaseAuditController.COMPANY)) {

            courseBaseLambdaQueryWrapper.eq(CourseBase::getCompanyId, companyId);
        }

        Page<CourseBase> page = this.page(courseBasePage, courseBaseLambdaQueryWrapper);
        List<CourseBase> records = page.getRecords();
        long total = page.getTotal();

        List<CourseBaseDTO> courseBaseDTOS = Collections.emptyList();
        if (!CollectionUtils.isEmpty(records)) {

            courseBaseDTOS = EntityMapper.INSTANCE.courseBaseToCourseBaseDToList(records);
        }
        PageVO pageVO = new PageVO(courseBaseDTOS,total,params.getPageNo(),params.getPageSize());

        return pageVO;
    }



    /*
    添加课程信息：
      1先判断是否需要事务（如果时增删改操作，必须要开始事务注解）
      2判断关键数据  （来源：1.数据库约束字段，2.前端页面的form表单 3.api接口文档）
      3判断业务数据（系统中存在数据，如果数据状态有问题，当前操作终止，一般来源于后端）
      4判断数值是否要被赋值（默认值） status：数据库已经有默认值，无需操作
	                audiStatus（审核状态）：默认未提交（状态码）
      5将dto转为po数据进行与mysql之间的操作（因为mybatis-plus只能对po数据进行操作）
      6保存数据并返回结果，判断结果是否成功
      7如果操作成功，将数据转为dto并返回给web层
     */
    @Override
    @Transactional
    public CourseBaseDTO creatCourse(CourseBaseDTO dto) {
        //判断关键数据是否为空（数据约束字段，前端传入的额数据，api文档）
        isKeyword(dto);


        //添加时的审核状态（AuditStatus）和删除状态（status）必须是未提交的和未删除的，数据库status默认值为1未删除
        dto.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());

        //进行跟数据库关联操作，把dto实体类转换为po实体类（mp只跟po实体类进行相关操作）
        CourseBase courseBase = EntityMapperPo.INSTANCE.courseBaseDTOToCourseBase(dto);
        //往数据库内存信息
        boolean courseSave = this.save(courseBase);
        if (!courseSave) {
            ExceptionCast.cast(ContentErrorCode.E_120001);
        }
        //因为前端涉及到两张表添加   所以要为营销表（courseMarke）添加数据
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        //添加收费标准
        String charge = dto.getCharge();
        courseMarket.setCharge(charge);
        //如果收费标准时收费状态，进行判断价格是否为空
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            Float price = dto.getPrice();
            if (ObjectUtils.isEmpty(price)) {
                ExceptionCast.cast(ContentErrorCode.E_120110);
            }
            courseMarket.setPrice(price);
        }
        //往数据库内保存营销数据
        boolean courseMakerSave = courseMarketService.save(courseMarket);
        if (!courseMakerSave) {
            ExceptionCast.cast(ContentErrorCode.E_120111);
        }

        //因为规定前端只接受DTO实体类的数据
           //所以要把po转换为dto返回给web层
             //根据id获取po最新数据 ，将po转换为dto ，为dto添加营销表的内容后返回给web层
        Long id = courseBase.getId();
        CourseBase courseBasePo = this.getById(id);
        CourseBaseDTO resultDTO = EntityMapper.INSTANCE.courseBaseToCourseBaseDTo(courseBasePo);
        resultDTO.setCharge(courseMarket.getCharge());
        resultDTO.setPrice(courseMarket.getPrice());
        return resultDTO;
    }



    /*
    根据courseid查询信息（数据回显）业务分析：
        1.判断关键数据 courseid（课程信息id）和companyid（机构id）是否为空
        2.判断业务数据课程基本信息和营销信息（1.判断课程是否存在，2.判断是否为同一家机构，3.判断staus状态是否是删除状态）
        3.查询到的数据转换为dto在返回给web
     */

    @Override
    public CourseBaseDTO updatequeryById(Long courseBaseId,Long companyId) {
        //判断课程id 和 机构id是否存在
        if (ObjectUtils.isEmpty(courseBaseId)) {
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }
        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }


        //判断该id的课程 是否存在 是否为同一家机构，staus状态是否是删除状态
        CourseBase courseBase = getIsCourseBase(courseBaseId, companyId);

        //po转换为dto
        CourseBaseDTO resultDTO = EntityMapper.INSTANCE.courseBaseToCourseBaseDTo(courseBase);

        //根据id获取营销表判断是否存在，收费状态下价格是否为空，把相关信息存入返回dto对象中
        getIscourseMark(courseBaseId, resultDTO);


        return resultDTO;
    }




    /*
    修改课程信息
        判断是否添加事务
        判断关键数据(可以使用添加的判断
            修改时：课程id是必须存在)
        判断业务数据(判断是否存在,判断是否是同一家教学机构,判断是否删除,判断课程审核状态：未提交、审核未通过)
        将dto数据转换为po数据与mysql进行修改操作(有些内容是不容修改的：courseId、companyid、auditstatus、status)
        判断修改后的数据是否符合
        把修改后的数据转换为dto
        将修改后的数据返回给web
     */

    @Override
    @Transactional
    public CourseBaseDTO updateCourseBase(CourseBaseDTO dto) {
        //判断关键数据是否为空（数据约束字段，前端传入的额数据，api文档）
        isKeyword(dto);
        //判断课程id是否为空
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())) {
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }

        // 判断该id的课程 是否存在 是否为同一家机构，staus状态是否是删除状态
        CourseBase isCourseBase = getIsCourseBase(dto.getCourseBaseId(), dto.getCompanyId());

        //判断课程审核状态：未提交、审核未通过,未发布
        if (isCourseBase.getAuditStatus().equals(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode()) ||
                isCourseBase.getAuditStatus().equals(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode()) ||
                isCourseBase.getAuditStatus().equals(CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode()))
        {
            ExceptionCast.cast(ContentErrorCode.E_120011);
        }


        //将dto转换为po  id，companyId，AutitStatus，Status设置为不可更改，修改相关数据
        CourseBase courseBase = EntityMapperPo.INSTANCE.courseBaseDTOToCourseBase(dto);
        courseBase.setCompanyId(null);
        courseBase.setAuditStatus(null);
        courseBase.setStatus(null);
        boolean b = this.updateById(courseBase);
        if (!b) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

        //利用mp修改营销表数据
        LambdaUpdateWrapper<CourseMarket> marketUpdateWrapper = new LambdaUpdateWrapper<>();
        marketUpdateWrapper.set(CourseMarket::getCharge, dto.getCharge());
        String charge = dto.getCharge();
        if (charge.equals(CourseChargeEnum.CHARGE_YES.getCode())) {
            Float price = dto.getPrice();
            if (ObjectUtils.isEmpty(price)) {
                ExceptionCast.cast(ContentErrorCode.E_120104);
            }
        }
        marketUpdateWrapper.set(CourseMarket::getPrice, dto.getPrice());
        marketUpdateWrapper.eq(CourseMarket::getCourseId, dto.getCourseBaseId());
        boolean update = courseMarketService.update(marketUpdateWrapper);
        if (!update) {
            ExceptionCast.cast(ContentErrorCode.E_120107);
        }

        // 将po转回dto存入最新数据返回给web
        CourseBaseDTO resultDTO = EntityMapper.INSTANCE.courseBaseToCourseBaseDTo(courseBase);
        getIscourseMark(resultDTO.getCourseBaseId(),resultDTO);
        return resultDTO;
    }


    /*
 根据courseid删除信息业务分析：
        1.判断关键数据 courseid（课程信息id）和companyid（机构id）是否为空
        2.判断业务数据课程基本信息和营销信息（1.判断课程是否存在，2.判断是否为同一家机构，3.判断staus状态是否是删除状态）
        3.判断是否为当前机构下的  是：执行逻辑删除  否：报错
     */
    @Override
    @Transactional
    public void deleteCourseBase(Long courseBaseId, Long companyId) {
        //判断课程id 和 机构id是否存在
        if (ObjectUtils.isEmpty(courseBaseId)) {
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }
        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }

        //判断该id的课程 是否存在 是否为同一家机构，staus状态是否是删除状态
        CourseBase courseBase = getIsCourseBase(courseBaseId, companyId);
        courseBase.setStatus(0);

        //判断课程审核状态：未提交、审核未通过,未发布
        if (courseBase.getAuditStatus().equals(CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode())) {
            ExceptionCast.cast(ContentErrorCode.E_120012);
        }
        if (!courseBase.getAuditStatus().equals(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode())) {
            ExceptionCast.cast(ContentErrorCode.E_120012);
        }
        if (courseBase.getAuditStatus().equals(CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode())) {
            ExceptionCast.cast(ContentErrorCode.E_120012);
        }

        if (companyId.equals(courseBase.getCompanyId())) {

            boolean b = this.updateById(courseBase);
            if (!b) {
                ExceptionCast.cast(ContentErrorCode.E_120021);
            }
        }
    }


    /*
    判断关键数据是否为空（数据约束字段，前端传入的额数据，api文档）
     */

    private void isKeyword(CourseBaseDTO dto) {
        if (StringUtil.isBlank(dto.getGrade())) {
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }
        if (StringUtil.isBlank(dto.getMt())) {
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }
        if (StringUtil.isEmpty(dto.getName())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }
        if (StringUtil.isBlank(dto.getSt())) {
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }
        if (StringUtil.isBlank(dto.getTeachmode())) {
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }
        if (StringUtil.isEmpty(dto.getUsers())) {
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        if (StringUtil.isBlank(dto.getCharge())) {
            ExceptionCast.cast(ContentErrorCode.E_120104);
        }
    }

    /*
   判断该id的课程 是否存在 是否为同一家机构，staus状态是否是删除状态
    */

    private CourseBase getIsCourseBase(Long courseId, Long companyId) {
        CourseBase courseBase = this.getById(courseId);
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        if (!courseBase.getCompanyId().equals(companyId)) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }
        if (courseBase.getStatus().equals(CommonEnum.DELETE_FLAG.getCodeInt())) {
            ExceptionCast.cast(ContentErrorCode.E_120112);
        }
        return courseBase;
    }

    /*
  根据id获取营销表判断是否存在，收费状态下价格是否为空，把相关信息存入返回dto对象中
    */

    private void getIscourseMark(Long courseId, CourseBaseDTO resultDTO) {
        LambdaQueryWrapper<CourseMarket> marketQueryWrapper = new LambdaQueryWrapper<>();
        marketQueryWrapper.eq(CourseMarket::getCourseId, courseId);
        CourseMarket courseMarket = courseMarketService.getOne(marketQueryWrapper);

        if (ObjectUtils.isEmpty(courseMarket)) {
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }
        resultDTO.setCourseBaseId(courseMarket.getCourseId());
        resultDTO.setCharge(courseMarket.getCharge());
        //判断收费类型下，价格是否为空
        if (courseMarket.getCharge().equals(CourseChargeEnum.CHARGE_YES.getCode())) {
            float price = courseMarket.getPrice();
            if (ObjectUtils.isEmpty(price)) {
                ExceptionCast.cast(ContentErrorCode.E_120110);
            }
            resultDTO.setPrice(courseMarket.getPrice());
        }
    }


    /*
        业务分析：审核前  必须：已提交
    *   1.判断关键数据
    *   2.判断业务数据
    *       课程基础信息
    *           判断是否存在
    *           判断是否是同一家教学机构
    *           判断是否删除
    *           判断审核状态
    *   3.修改课程审核状态
    *       已提交
     */

    @Override
    @Transactional
    public void updateAuditStatus(Long courseId, Long companyId) {
        //    *   1.判断关键数据
        if (ObjectUtils.isEmpty(companyId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //    *   2.判断业务数据
        //    *       课程基础信息
        //    *           判断是否存在
        //    *           判断是否是同一家教学机构
        //    *           判断是否删除
        //    *           判断审核状态
        CourseBase courseBase = this.getById(courseId);
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        if (!companyId.equals(courseBase.getCompanyId())) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120112);
        }
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus()))
        {
         ExceptionCast.cast(ContentErrorCode.E_120011);
        }

        //    *   3.修改课程审核状态
        //    *       已提交
        if (!CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus())) {
            LambdaUpdateWrapper<CourseBase> courseBaseUpdateWrapper = new LambdaUpdateWrapper<>();
            courseBaseUpdateWrapper.eq(CourseBase::getId, courseId)
                    .eq(CourseBase::getCompanyId, companyId)
                    .set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode())
                    .set(CourseBase::getChangeDate, LocalDateTime.now());
            boolean update = this.update(courseBaseUpdateWrapper);
            if (!update) {
                ExceptionCast.cast(ContentErrorCode.E_120017);
            }
        } else {

            ExceptionCast.cast(ContentErrorCode.E_120023);
        }

    }


    /*
        业务分析：
    *   1.判断关键数据
    *       auditMind  auditStatus  courseid
    *
    *   2.判断业务数据
    *       课程基础信息
    *           判断是否存在
    *           判断是否删除
    *           判断审核状态
    *               必须为：已提交
    *       审核状态
    *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
    *   3.修改课程审核信息
    *       auditMind  auditStatus  auditNum（每次+1）
     */
    @Override
    @Transactional
    public void selectOrUpdateAuditStatus(CourseBaseDTO dto) {
        //    *   1.判断关键数据
        //    *       auditMind  auditStatus  courseid
        if (StringUtil.isBlank(dto.getAuditMind())) {
            ExceptionCast.cast(ContentErrorCode.E_120024);
        }
        if (ObjectUtils.isEmpty(dto.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120025);
        }
        //    *   2.判断业务数据
        //    *       课程基础信息
        //    *           判断是否存在
        //    *           判断是否删除
        //    *           判断审核状态
        //    *               必须为：已提交
        //    *       审核状态
        //    *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
        CourseBase courseBase = this.getById(dto.getCourseBaseId());
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120112);
        }
//
        if (CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(dto.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120026);
        }
//
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(dto.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120026);
        }


        if (CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode().equals(dto.getAuditStatus()) || CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(dto.getAuditStatus())) {
            //    *   3.修改课程审核信息
            //    *       auditMind  auditStatus  auditNum（每次+1）
//            Integer auditNums = dto.getAuditNums();
//            if (ObjectUtils.isEmpty(auditNums)) {
//                auditNums = 0;
//            }
//            int increment = increment(auditNums.toString());
//            if (increment == 0) {
//                increment = increment(auditNums.toString());
//            }
            //redis优化audinum
            Long increment = redisTemplate.opsForValue().increment("auditNum:" + dto.getCourseBaseId());

            LambdaUpdateWrapper<CourseBase> courseBaseWrapper = new LambdaUpdateWrapper<>();
                courseBaseWrapper.eq(CourseBase::getId, dto.getCourseBaseId())
                        .set(CourseBase::getAuditMind, dto.getAuditMind())
                        .set(CourseBase::getAuditStatus, dto.getAuditStatus())
                        .set(CourseBase::getAuditNums, increment.intValue())
                        .set(CourseBase::getChangeDate, LocalDateTime.now());
                boolean update = this.update(courseBaseWrapper);
                if (!update) {
                    ExceptionCast.cast(ContentErrorCode.E_120017);
                }

        }
    }

//    /*
//        redis实现数字自增方法
//     */
//    public  int increment(String key){
//        RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(key, redisTemplate.getConnectionFactory());
//        int andIncrement = redisAtomicInteger.getAndIncrement();
//        //初始设置过期时间
////        if(andIncrement==0&&liveTime>0){
////            redisAtomicInteger.expire(liveTime, TimeUnit.SECONDS);
////        }
//        return andIncrement;
//    }
}
